package com.ls.shiro;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Sets;
import com.ls.util.SerializeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.*;

import static com.ls.common.Const.KEY_SHIRO_REDIS;

/**
 * <p>shiro redis cache</p>
 * Created by zhezhiyong@163.com on 2017/2/22.
 */
@Slf4j
public class ShiroRedisCache<K, V> implements Cache<K, V> {

    private RedisTemplate<String, V> redisTemplate;
    private String prefix = KEY_SHIRO_REDIS;

    public ShiroRedisCache(RedisTemplate<String, V> redisTemplate, String prefix) {
        this.redisTemplate = redisTemplate;
        this.prefix = prefix;
    }

    public ShiroRedisCache(RedisTemplate<String, V> redisTemplate) {
        this(redisTemplate, KEY_SHIRO_REDIS);
    }

    private String getByteKey(K k) {
        if (k instanceof String) {
            String preKey = getPrefix() + k;
            return preKey;
        } else if (k instanceof SimplePrincipalCollection) {
            System.out.println("SimplePrincipalCollection: "+k.toString());
            return k.toString();
//            ShiroRealm
//            Set set = (Set) ((SimplePrincipalCollection) k).fromRealm("com.ls.shiro.ShiroRealm_0");
//            System.out.println("JSON.toJSONString(set) = " + JSON.toJSONString(set));
        } else {
            if (log.isDebugEnabled()) {
                log.debug("k is not String: {}", k);
            }
            return k.toString();
//            return SerializeUtils.serialize(k);
        }
//        return "";
    }

    @Override
    public V get(K k) throws CacheException {
        if (log.isDebugEnabled()) log.debug("key: {}", k);
        if (null == k) return null;
        String bKey = getByteKey(k);
        return redisTemplate.opsForValue().get(bKey);
    }

    @Override
    public V put(K k, V v) throws CacheException {
        if (log.isDebugEnabled()) log.debug("key: {}, value: {}", k, v);
        if (null == k || null == v) return null;
        String bKey = getByteKey(k);
        redisTemplate.opsForValue().set(bKey, v);
        return v;
    }

    @Override
    public V remove(K k) throws CacheException {
        if (log.isDebugEnabled()) log.debug("key: {}", k);
        if (null == k) return null;
        String bKey = getByteKey(k);
        V v = redisTemplate.opsForValue().get(bKey);
        redisTemplate.delete(bKey);
        return v;
    }

    @Override
    public void clear() throws CacheException {
        redisTemplate.getConnectionFactory().getConnection().flushDb();
    }

    @Override
    public int size() {
        Long len = redisTemplate.getConnectionFactory().getConnection().dbSize();
        return len.intValue();
    }

    @Override
    public Set<K> keys() {
//        byte[] bKey = (getPrefix() + "*").getBytes();
//        Set<byte[]> set = redisTemplate.keys(bKey);
//        Set<K> result = Sets.newHashSet();
//
//        if (CollectionUtils.isEmpty(set)) {
//            return Collections.emptySet();
//        }
//
//        for (byte[] key : set) {
//            result.add((K) key);
//        }
//        return result;
        throw new UnsupportedOperationException();
    }

    @Override
    public Collection<V> values() {
//        Set<K> keys = keys();
//        List<V> values = new ArrayList<>(keys.size());
//        for (K k : keys) {
//            byte[] bKey = getByteKey(k);
//            values.add(redisTemplate.opsForValue().get(bKey));
//        }
//        return values;
        throw new UnsupportedOperationException();
    }

    public String getPrefix() {
        return prefix;
    }

    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }
}
